#include <opencv2/opencv.hpp>
#include <iostream>
#include <string>
#include "aip-cpp-sdk/face.h"
#include <unistd.h>

using namespace cv;
using namespace std;

Mat image;
pthread_mutex_t image_mutex = PTHREAD_MUTEX_INITIALIZER;

Rect faceRange;
pthread_mutex_t range_mutex = PTHREAD_MUTEX_INITIALIZER;

int detected = 0;

void *thread(void *arg)
{
	vector<Rect> faces;
	string app_id = "19857515";
	string api_key = "HbMn5OnXW5Uxb7sC13mdrYNr";
	string secret_key = "ebW29zXKsVcD6OBkiGDuwtHn2aGIbs4N";
	aip::Face client(app_id, api_key, secret_key);
	Mat cam_image;
	CascadeClassifier classifier;

	classifier.load("/usr/share/opencv/haarcascades/haarcascade_frontalface_alt2.xml");

	while (1)
	{
		Mat gray;

		pthread_mutex_lock(&image_mutex);
		cam_image = image;
		pthread_mutex_unlock(&image_mutex);

		cvtColor(image, gray, COLOR_BGR2GRAY);
		equalizeHist(gray, gray);
		classifier.detectMultiScale(gray, faces);
		if (faces.size())
		{
			pthread_mutex_lock(&range_mutex);
			faceRange = faces[0];
			pthread_mutex_unlock(&range_mutex);
			detected++;
		}
		else
		{
			detected = 0;
		}

		if (detected == 3)
		{
			Mat face(cam_image, faceRange);
			vector<unsigned char> buf;

			detected = 0;
			imencode(".jpg", face, buf);
			string faceimg = aip::base64_encode((char *)buf.data(), buf.size());
			Json::Value json = client.search(faceimg, "BASE64", "group1", aip::null);
			cout << json["result"]["user_list"][0]["user_id"] << endl;
		}

		usleep(200000);
	}
}

int main(void)
{
	VideoCapture cam;
	pthread_t tid;
	cam.open(0);
	namedWindow("Camera", WINDOW_NORMAL);
	setWindowProperty("Camera", WND_PROP_FULLSCREEN, WINDOW_FULLSCREEN);

	cam >> image;
	pthread_create(&tid, nullptr, thread, nullptr);

	while (1)
	{
		pthread_mutex_lock(&image_mutex);
		cam >> image;
		pthread_mutex_unlock(&image_mutex);

		if (detected)
		{
			pthread_mutex_lock(&range_mutex);
			rectangle(image, faceRange, CV_RGB(255, 0, 0));
			pthread_mutex_unlock(&range_mutex);
		}
		resize(image, image, Size(1024, 768));
		imshow("Camera", image);
		if (waitKey(40) != 255)
		{
			break;
		}
	}

	return 0;
}

